﻿using BeetleX.FastHttpApi;
using purchase.Oversell;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace purchase
{
    //class Startup
    //{
    //    public void ConfigureServices(IServiceCollection services)
    //    {
    //        services.AddControllers();
    //    }
    //    public void Configure(IApplicationBuilder app)
    //    {
    //        app.UseEndpoint(endpoints =>
    //        {
    //            endpoints.MapControllers();
    //        });
    //    }
    //}

    [Controller]
    class Program
    {
        static IFreeSql fsql;
        static HttpApiServer mApiServer;
        // Get /hello?name=henry 
        // or
        // Get /hello/henry
        [Get(Route = "{name}")]
        public object Hello(string name)
        {
            return $"hello {name} {DateTime.Now}";
        }

        // Get /GetTime  
        public object GetTime()
        {
            return DateTime.Now;
        }

        //1w并发
        //ab -n 20000 -c 10000 http://127.0.0.1:9090/coupon/1
        //提供接口给ab做Http并发测试
        [Get(Route = "{id}")]
        public string coupon(int id = 1)
        {
            var q = fsql.Update<product>().Set(c => c.total - 1).Where(c => c.id == id && c.total > 0).ExecuteAffrows();

            var idvalue = fsql.Insert<purchase>(new purchase()
            {
                ip = Guid.NewGuid().ToString("N"),
                amount = 1,
                productid = id,
                remark = q > 0 ? "抢购成功" : "抢购失败"
            }).ExecuteIdentity();

            fsql.Ado.ExecuteNonQuery($"update coupon set total=total+1,pcid={idvalue} where total=0 limit 1");
            return q > 0 ? "抢购成功" : "抢购失败";
        }

        static void Main(string[] args)
        {
            Console.WriteLine("purchase");
            Console.WriteLine();

            Console.WriteLine("-----------InterTest-----------");
            InterTest.Test();
            Console.WriteLine();
            Console.WriteLine();

            Console.WriteLine("-----------超卖演示-----------");
            OversellFail.Test();
            Console.WriteLine();

            Console.WriteLine("-----------Lock锁-----------");
            OversellSuccessLock.Test();
            Console.WriteLine();

            Console.WriteLine("-----------InterLock原子锁-----------");
            OversellSuccessInterLock.Test();
            Console.WriteLine();

            Console.WriteLine("-----------Redis原子锁演示-----------");
            OversellSuccessRedis.Test();

            Console.ReadKey();

            Console.WriteLine("-----------通过FastHttpApi暴露接口，然后用AB测试-----------");
            fsql = new FreeSql.FreeSqlBuilder()
            .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=qwer1234;Initial Catalog=myshop;Charset=utf8;SslMode=none;")
            .Build(); //请务必定义成 Singleton 单例模式

            mApiServer = new BeetleX.FastHttpApi.HttpApiServer();
            mApiServer.Options.LogLevel = BeetleX.EventArgs.LogType.Trace;
            mApiServer.Options.LogToConsole = true;
            mApiServer.Register(typeof(BeetleX.FastHttpApi.Admin._Admin).Assembly);
            mApiServer.Register(typeof(Program).Assembly);
            //mApiServer.Options.Port=80; set listen port to 80
            mApiServer.Open();//default listen port 9090  
            Console.Write(mApiServer.BaseServer);
            Console.Read();

            //FreeSql.Generator -Razor 1 -NameOptions 0,0,0,0 -NameSpace MyProject -DB "MySql,Data Source=127.0.0.1;Port=3306;User ID=root;Password=qwer1234;Initial Catalog=myshop;Charset=utf8;SslMode=none;"

            //Try();

            Console.ReadKey();
        }

        static void Try()
        {
            //普通并发购买
            //Parallel.Invoke(TryPurchase, TryPurchase);

            //生成优惠卷
            //Parallel.Invoke(GenerateCoupon);

            //抢购优惠卷
            //Task task1 = new Task(() => { TrtCoupon(0, 1000); });

            //Task task2 = new Task(() => { TrtCoupon(10000, 20000); });

            //task1.Start();
            //task2.Start();
        }

        public static void TrtCoupon(int start = 0, int end = 10000)
        {
            var product = fsql.Select<product>().First();

            CancellationToken cancellationToken = new CancellationToken();

            Parallel.For(start, end, new ParallelOptions() { MaxDegreeOfParallelism = 50, CancellationToken = cancellationToken }, i =>
            {
                var q = fsql.Update<product>().Set(c => c.total - 1).Where(c => c.id == product.id && c.total > 0).ExecuteAffrows();

                var idvalue = fsql.Insert<purchase>(new purchase()
                {
                    ip = i.ToString(),
                    amount = 1,
                    productid = product.id,
                    remark = q > 0 ? "抢购成功" : "抢购失败"
                }).ExecuteIdentity();

                fsql.Ado.ExecuteNonQuery($"update coupon set total=total+1,pcid={idvalue} where total=0 limit 1");
            });

            Console.WriteLine("完成");
        }

        public static void GenerateCoupon()
        {
            Parallel.For(0, 10000, new ParallelOptions() { MaxDegreeOfParallelism = 50 }, i =>
            {
                fsql.Insert<coupon>(new coupon()
                {
                    code = Guid.NewGuid().ToString("N"),
                    total = 0
                }).ExecuteAffrows();
            });
        }

        public static void TryPurchase()
        {
            var product = fsql.Select<product>().First();

            CancellationToken cancellationToken = new CancellationToken();

            Parallel.For(0, 10000, new ParallelOptions() { MaxDegreeOfParallelism = 50, CancellationToken = cancellationToken }, i =>
            {
                var q = fsql.Update<product>().Set(c => c.total - 1).Where(c => c.id == product.id && c.total > 0).ExecuteAffrows();

                fsql.Insert<purchase>(new purchase()
                {
                    ip = i.ToString(),
                    amount = 1,
                    productid = product.id,
                    remark = q > 0 ? "抢购成功" : "抢购失败"
                }).ExecuteAffrows();

                //只能100个抢
                //if (q > 0)
                //{
                //    fsql.Insert<purchase>(new purchase()
                //    {
                //        ip = i.ToString(),
                //        amount = 1,
                //        productid = product.id
                //    }).ExecuteAffrows();
                //}
            });
        }
    }
}
